Naukri Local Judge Mod
開始使用
這是什麼? 能做什麼?
這是一個 C/C++的本地 Judge 模組,它可以在輸入結束後自動幫你比對測資,免除線上判斷時的麻煩和等待時間。
他能夠幫助你:
- 取消 4996 警告(scanf()等函式的不安全警告)
- 取消 scanf() 不接受回傳值時的警告
- 本地 Judge (支援 Tolerant 、 Strictly 、 Special 三種模式)
- 簡單的效能評估
安裝
以下為在 Visual Studio 安裝的流程
下載本模組
新增一個空白專案,並在專案中加入一個名為 main 的.c 或.cpp 檔
新增 include 目錄到專案
專案 → 屬性 → C/C++ → 一般 → 其他 Include 目錄 → 指定模組資料夾
把模組中的 systemInput.txt、systemOutput.txt、userOutput.txt 移動至專案資料夾 (你寫程式的.c/.cpp 檔那裡)。
以 Project 專案為例,在 Project/Project/ 這層會看到 main.c,把 3 個 txt 檔丟到這裡。
如果使用的是 cpp,將模組中全部的.c 檔改為.cpp。
侵入式安裝
這步驟不會為你添加任何實質性的功能,但可以在寫程式時不用再引入本模組的標頭檔,從而獲得更好的使用體驗,但如果除了 Online Judge 之外還要寫其他 C/C++的程式則不建議使用。
先備份好 stdio.h 避免出錯。
做完以上述動作後,開啟 main.c 輸出
#include <stdio.h>
在上面右鍵 → 前往<stdio.h>
滑到最下面,在#endif 上加上
#include <naukri.h>
變成
… (其他在上面的程式碼)
#include <naukri.h>
#endif儲存,如果你的 Visual Studio 沒有該資料夾的存取權限他會提示你另存新檔,把它存到桌面在手動貼到該資料夾覆蓋即可。
資料夾可以在 stdio.h 頁籤上右鍵 → 開啟收納資料夾找到。
操作
使用方式
選好 Judge 模式(參見判斷模式),在#include <stdio.h> 下引入 naukri.h 變成
即可使用,上傳至 OJ 時記得刪掉 #include <naukri.h> 就可以了。
若為侵入式安裝則不必引入(除非你不會用到 stdio.h),像沒安裝模組時一樣寫程式即可。
若你使用的是 cpp,iostream 和 cstdio 內部都會引入 stdio.h。
情境範例
請先閱讀下方的巨集與定義
已經有輸入和正確的輸出
- 在 FILE_INPUT 放輸入,在 FILE_COMPARE 放正確的輸出
- 定義 IO 模式為 F_TF (FILE_INPUT 輸入、終端 + FILE_OUTPUT 輸出)
- 將 CMPMODE 設為 2 (或將函式 main() return 2)
- 開始運行。
已經有輸入和正確的程式碼
- 在 FILE_INPUT 放輸入
- 定義 IO 模式為 F_TF (FILE_INPUT 輸入、終端 + FILE_OUTPUT 輸出)
- 將 CMPMODE 設為 3 (或將函式 main() return 3)
- 開始運行。
只有正確的程式碼,想用終端機測試
- 定義 IO 模式為 T_TF (終端輸入、終端 + FILE_OUTPUT 輸出)
- 將 CMPMODE 設為 3 (或將函式 main() return 3)
- 開始運行,輸入自定義測資。 (也可以將自定義測資放到 FILE_INPUT 用 “已經有輸入和正確的程式碼” 判斷)
什麼都沒有,只是想使用包裝過的函式
- 定義 IO 模式為 T_T (終端輸入、終端輸出)
- 將 CMPMODE 設為 1 (或將函式 main() return 1)
- 開始運行。
巨集與定義
判斷模式
比較時的預設參數。
CMPMODE
定義預設的 Judge 的方式,而 main.c 的 return 值可以用來覆蓋這個預設模式(也就是如果 return 不為 0 則以 return 值為準)
0 = 隨意(若 return 亦為 0 則不進行比較)
1 = 不進行比較
2 = 使用 FILE_COMPARE 儲存的答案比較
3 = 使用 judge.c 計算出的答案比較 (這個模式只有在使用 FILE_INPUT 作為輸入時才能使用)
4 = 自動判斷,如果輸入來自終端機 = 2, 來自檔案 = 3
STRICTLYMODE
嚴格比對模式,當 STRICTLYMODE 為 0 時代表關閉,亦即是寬容(Tolerant)模式,為 1 時開啟則是嚴格(Strictly)模式,預設值為 0
TLE
定義超時時間限制,以毫秒為單位,預設值為 1000 ms
注意!它不會在你超時時跳出程式,只會在印出判斷結果時提醒你超時了。
文件位置
輸入輸出檔存放位置,可在 naukri.h 進行自定義修改
FILE_INPUT
輸入檔位置,預設值為 input.txt
FILE_OUTPUT
使用者輸出檔位置,預設值為 output.txt
FILE_COMPARE
比對用檔案位置,也是判斷程式輸出檔,預設值為 compare.txt
IO 流
這部分僅供模組使用,若無客製化需求只要注意不要誤用關鍵字即可。
stdin
當輸入選擇 FILE_INPUT 時會覆寫 stdio.h 對 stdin 的定義。
本巨集僅用於將 freed() 等未被包裝的輸入函式指向正確的輸入位置,在被包裝的函式中,內部會強制將流導向定義的 fileIn 或 termIn 。
termIn
終端輸入流
termOut
終端輸出流
termErr
終端錯誤流
fileIn
檔案輸入流
fileOut
檔案輸出流
fileCmp
檔案比對流
IO 修正
LFFIX
定義是否將 gets(),fgets() 讀入字串末端的換行符號 ('\n') 移除
0 = 不移除字串尾的換行符號
1 = 移除字串尾的換行符號
IO 模式
使用 wrapper 包裝平常會使用到的輸入輸出方式。
IO 模式是預設為 F_TF,你可以在 naukri.h 進行更改,若只是要暫時的更改做測試則在 main.c 的 #include <naukri.h> 之前定義你要的模式 Ex:
就會變成 F_TF 模式。
NO_WRAPPER
不包裝,也就是使用原生的 IO 模式
T_T
使用終端機作為輸入,並將結果輸出至終端機,和不包裝一樣,差別在它能讓不接受回傳值時的警告消失。
T_F
使用終端機作為輸入,並將結果輸出至 FILE_OUTPUT。
T_TF
使用終端機作為輸入,並將結果輸出至終端機和 FILE_OUTPUT。
F_T
使用 FILE_INPUT 作為輸入,並將結果輸出至終端機。
F_F
使用 FILE_INPUT 作為輸入,並將結果輸出至 FILE_OUTPUT。
F_TF
使用 FILE_INPUT 作為輸入,並將結果輸出至終端機和 FILE_OUTPUT。
F_C
使用 FILE_INPUT 作為輸入,並將結果輸出至 FILE_COMPARE,這是給 judge.c 使用的巨集。
F_TC
使用 FILE_INPUT 作為輸入,並將結果輸出至終端機和 FILE_COMPARE,這是給 judge.c 使用的巨集。
被包裝的函式
除了輸入輸出(參照IO 模式)位置外,他們不會對你的程式造成任何影響,你可以像沒有包裝時一樣使用他們。但要注意為了讓模組能夠正常的運行,這些被包裝的函式可能會產生額外的運算。
- scanf(_Format, …)
- gets(_Buffer)
- fgets(_Buffer, _MaxCount, _Stream)
- getchar()
- printf(_Format, …)
- puts(_Buffer)
- putchar(_Character)
注意事項
judge.c 最上方會有預設的引入,這是使用程式碼進行判斷時的必要引入,請不要將它刪掉,如果不慎誤刪在 naukri.h 最底部有一個被註解掉的備份可以還原。
時間判斷是使用 CPU 的 clock 數來計算,因此在終端機等候輸入和使用中斷點 Debug 的時都會被計入,若想要獲得較正確的時間評估請使用 FILE_INPUT 做輸入並關閉所有中斷點。
模組中使用的全域函式或變數皆以雙底線開頭、單底線結尾(__func_()),是為了避免和使用者定義的函式衝到,請不要使用這種命名方式。
main.c 的 main() 會被用巨集定義成 __main_()、 judge.c 的 main() 則會被定義成 __judge_(),這些是為了先載入模組的必要定義,模組載入後會自己呼叫 __main_() 和 __judge_() ,不必擔心。
如果 main.c 和 judge.c 的變數或函式撞名,系統會報錯並顯示該變數(函式)已經在 judge.obj 定義過了,這時候只要把 judge.c 裡面的撞名變數(函式)前面加上 static 前綴即可。